package momo.app.structure;

import java.net.InetAddress;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import momo.multitree.structure.Edge;
import momo.multitree.structure.Graph;
import momo.multitree.structure.Node;

public class PeerList extends Graph
{
	private Log log = LogFactory.getLog(PeerList.class);
	
	public PeerList()
	{
		super();
	}
	
	public boolean add(Peer peer)
	{
		if ( !isPeerExist(peer.getId()) )
			return super.add(peer);
		return false;
	}
	
	public boolean add(PeerLink link)
	{
		if ( getPeerLink(link.getSource().getId(), link.getDest().getId()) == null )
		{
			return super.add(link);
		} 
		return false;
	}
	
	public boolean addPeerLink(PeerLink link)
	{
		return addPeerLink(link.getSource().getId(), 
						link.getDest().getId(), 
						link.getCost(), 
						link.getLatency());
	}
	
	public boolean addPeerLink(String source_id, String dest_id, double cost, double lat)
	{
		if ( log.isDebugEnabled() ) {
			log.debug("source_id: " + source_id);
			log.debug("dest_id: " + dest_id);
		}
		if ( getPeerLink(source_id, dest_id) == null )
		{
			Peer source = getPeer(source_id);
			Peer dest = getPeer(dest_id);
			if ( source != null && dest != null )
			{
				PeerLink link = new PeerLink(source, dest, cost, lat);
				return super.add(link);
			}
		}else
		{
			return updatePeerLink(source_id, dest_id, cost, lat);
		}
		return false;
	}
	
	public boolean updatePeerWorkloadRate(String id, double workloadRate)
	{
		if ( isPeerExist(id) )
		{
			Peer p = getPeer(id);
			p.setWorkloadRate(workloadRate);
			return true;
		}
		return false;
	}
	
	public boolean incrementPeerWorkload(String id)
	{
		if ( isPeerExist(id) )
		{
			Peer p = getPeer(id);
			if (p == null) {
				if ( log.isErrorEnabled() )
					log.error("incrementWorkload: peer exists but not found: "+id);
				return false;
			}
			else {
				p.incrementWorkload();
				return true;
			}
		}
		if ( log.isErrorEnabled() )
			log.error("incrementWorkload: peer not found: "+id);
		return false;
	}
	
	public boolean updatePeerStability(String id, double stability)
	{
		if ( isPeerExist(id) )
		{
			Peer p = getPeer(id);
			p.setStability(stability);
			return true;
		}
		return false;
	}
	
	public boolean updatePeer(String id, double workload, double stability)
	{
		if ( isPeerExist(id) )
		{
			Peer p = getPeer(id);
			p.setWorkloadRate(workload);
			p.setStability(stability);
			return true;
		}
		return false;
	}
	
	public boolean updatePeerAddressToUse(String id, InetAddress addressToUse)
	{
		if ( isPeerExist(id) )
		{
			Peer p = getPeer(id);
			p.setAddressToUse(addressToUse);
			return true;
		}
		return false;
	}
	
	public boolean updatePeerLinkCost(String source_id, String dest_id, double cost)
	{
		PeerLink link = getPeerLink(source_id, dest_id);
		if ( link != null )
		{
			link.setCost(cost);
			return true;
		}
		return false;
	}
	
	public boolean updatePeerLinkLatency(String source_id, String dest_id, double latency)
	{
		PeerLink link = getPeerLink(source_id, dest_id);
		if ( link != null )
		{
			link.setLatency(latency);
			return true;
		}
		return false;
	}
	
	public boolean updatePeerLink(String source_id, String dest_id, double cost, double latency)
	{
		PeerLink link = getPeerLink(source_id, dest_id);
		
		if ( link != null )
		{
			link.setCost(cost);
			link.setLatency(latency);
			return true;
		}
		return false;
	}
	
	public boolean removePeer(String id)
	{
		Peer peer = this.getPeer(id);
		if ( peer != null )
			return super.remove(peer);
		return false;
	}
	
	public boolean removePeerLink(String source_id, String dest_id)
	{
		PeerLink link = this.getPeerLink(source_id, dest_id);
		if ( link != null )
			return super.remove(link);
		return false;
	}
	
	public boolean remove(Peer peer)
	{
		return this.removePeer(peer.getId());
	}
	
	public boolean remove(PeerLink link)
	{
		return this.removePeerLink(link.getSource().getId(), link.getDest().getId());
	}
	
	public boolean isPeerExist(String id)
	{
		Set<Peer> set = this.getPeers();
		Iterator<Peer> iter = set.iterator();
		while ( iter.hasNext() )
		{	
			if ( iter.next().getId().equals(id) )
				return true;
		}
		return false;
	}
	
	public Peer getPeer(String id)
	{
		if ( isPeerExist(id) )
			return (Peer)super.getNode(id);
		return null;
	}
	
	public PeerLink getPeerLink(String source_id, String dest_id)
	{
		Peer p1 = this.getPeer(source_id);
		Peer p2 = this.getPeer(dest_id);
		if ( p1 != null && p2 != null)
			return (PeerLink)super.getEdge(p1, p2);
		return null;
	}
	
	public Set<Peer> getPeers()
	{
		Set<Peer>set = new LinkedHashSet<Peer>();
		Iterator<Node> iter = super.getNodes().iterator();
		while ( iter.hasNext() )
			set.add((Peer)iter.next());
		return Collections.unmodifiableSet(set);
		
	}
	
	public Set<PeerLink> getPeerLinks()
	{
		Set<PeerLink> linkSet = new LinkedHashSet<PeerLink>();
		Iterator<Edge> iter = super.getEdges().iterator();
		while (iter.hasNext())
			linkSet.add((PeerLink)iter.next());
		return Collections.unmodifiableSet(linkSet);
	}
	
}//end of class PeerList
